

import React, { useState, useEffect } from 'react'
import randomList, { getPageData } from "../utils/randomList"


// 获取范围内的数据：
// 通过scrollTop以及pageSize计算开始和start开始到end结束展示的范围
// 计算范围时，考虑前后buffer加上pageSize
const getListRange = (option, start, scrollTop) => {
    let { list, pageSize, liHeight } = option
    let end = start + pageSize

    if(typeof scrollTop !== "undefined"){
        // const { showLength, liHeight } = this

        // 向前冗余N条数据，向后冗余N条数据
        let top = 0
        if(start > pageSize){
            top = scrollTop - (liHeight * pageSize)
            start = start - pageSize
        }
        else{
            top = (scrollTop < liHeight) ? 0 : scrollTop
        }
        end = end + pageSize

        let nodes = list.slice(start, end)

        return nodes.map((item, index) => {
            item.top = top
            return item
        }) 
    }

    return list.slice(start, end)
}


// 页面标记：上一次滑到的索引，该页数据是否已获取过
let start = 0
let fetched = {}

// 滚动事件
const onScroll = (option, target, setOption, setData, getList) => {
    const { liHeight, pageSize } = option
    const scrollTop = target.scrollTop
    const current = parseInt(scrollTop/liHeight)
    const pageNum = parseInt(current/pageSize) + 2
    const preBuffer = (start > pageSize) ? pageSize : 0
    const nxtBuffer = pageSize
    console.log("scrollTop:", scrollTop)
    console.log("current - start:", current - start)

    // 1、已经加载过的数据
    const scrollCache = () => {
        // 向上滑动，滑到一页的位置
        if(start - current > preBuffer - 2){
            updateRender()
        } 
    
        // 向下滑动，滑到一页的位置
        if(current - start > nxtBuffer - 2) {
            updateRender()
        }
    }

    // 2、未加载过的数据
    const scrollFetching = () => {
        // 向下滑动：请求数据，如果正在请求数据或者已有缓存就不请求
        if(current > start && fetched[pageNum] !== "fetching") {
            fetched[pageNum] = "fetching"

            let p = getList && getList({
                pageSize,
                pageNum
            })
            if(p instanceof Promise){
                p.then((list)=>{
                    option.list = option.list.concat(list)
                    updateRender()
                    fetched[pageNum] = "done"
                })
            } else {
                option.list = option.list.concat(p)
                updateRender()
                fetched[pageNum] = "done"
            }
        }
    }
    
    // 更新 option 和 data
    const updateRender = () => {
        const data = getListRange(option, current, scrollTop)
        const ops = updatePage(option)
        // 两个更新方法是否会合并？
        setData(data)
        setOption(ops)
        start = current
    }


    // 正在获取数据则不继续
    // 已经获取过数据的页面
    if(fetched[pageNum] === "done"){
        scrollCache()
    } else {
        scrollFetching()
    }
}

// 更新页面参数：首次渲染过后更新容器高度，元素高度等
const updatePage = (option) => {
    let { list, pageSize, boxHeight, ulHeight, liHeight, ulElement } = option

    // 只在首次渲染更新数据
    if(!liHeight){
        const nodes = document.getElementsByClassName("scroll-list-ul-li")
        if(nodes && nodes[0]){
            liHeight = nodes[0].clientHeight
            ulHeight = list.length * liHeight
            pageSize = parseInt(parseInt(boxHeight)/liHeight)

            return {
                ...option,
                ulHeight,
                pageSize,
                liHeight
            }
        }
        return option
    } else {
        // 分页加载时更新页面高度
        ulHeight = list.length * liHeight

        return {
            ...option,
            ulHeight
        }
    }
}

// 首次渲染
const initState = (option) => {
    return getListRange(option, 0)
}

export default function ScrollComponent(props) {
    let ulElement = React.createRef();

    let initOption = {
        list: props.list,
        pageSize: 20,
        boxHeight: window.screen.height - 50,
        ulHeight: 2000,
        liHeight: null,
        ulElement
    }
    let initData = initState(initOption)

    // 初始化
    let [option, setOption] = useState(initOption)
    let [data, setData] = useState(initData)

    // console.log("option:", option)
    // console.log("data:", data)

    // 生命周期：componentDidMount 
    useEffect(() => {
        const ops = updatePage(option)
        setOption(ops)

        
        const onOscroll = (e) => {
            const target = e.target.scrollingElement
        
            onScroll(ops, target, setOption, setData, (page)=>{
                console.log("page:", page)
                return props.onScroll && props.onScroll(page)
            })
        }
        // 首次渲染之后启动滚动事件监听
        // props.onScroll 为滚动事件对外接口，发起请求后回传数据
        document.addEventListener("scroll", onOscroll)

        return () => {
            document.removeEventListener("scroll", onOscroll)
        }
    }, [])


    return (
        <div className="scroll-list" ref={ulElement}  style={{
            position: "relative",
            height: option.boxHeight + "px"
        }}>
            <div className="scroll-list-ul"style={{
                height: option.ulHeight + "px"
            }}>
                {data.map((item, index)=>{
                    const key = item.key || item.id || index
                    return <div
                      className="scroll-list-ul-li"
                      style={{
                        position: "relative",
                        top: item.top + "px"
                      }} 
                      key={key}
                    >{item.name}</div>
                })}
            </div>
        </div>
    )
}


